package com.wangsd.web.shop.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.fastmybatis.core.query.Sort;
import com.gitee.fastmybatis.core.util.MyBeanUtil;
import com.wangsd.common.component.WxApiV3CouponService;
import com.wangsd.common.component.WxpayService;
import com.wangsd.common.exception.BusinessException;
import com.wangsd.common.utils.DateUtils;
import com.wangsd.common.utils.MD5Utils;
import com.wangsd.web.shop.entity.*;
import com.wangsd.web.shop.mapper.CouponMapper;
import com.wangsd.web.sys.entity.SysCompany;
import com.wangsd.web.sys.entity.UploadFile;
import com.wangsd.web.sys.service.SysCompanyService;
import com.wangsd.web.sys.service.UploadFileService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
public class CouponService {
    @Value("${notify_url}")
    private String notify_url;
    @Resource
    private CouponMapper mapper;
    @Autowired
    private UploadFileService uploadFileService;
    @Autowired
    private SysCompanyService companyService;
    @Autowired
    private TradeService tradeService;
    @Autowired
    private CouponOrderService couponOrderService;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    MemberService memberService;
    @Autowired
    MemberIntegralService memberIntegralService;
    @Autowired
    private CustomerService customerService;



    public Coupon selectById(Long id) {
        return mapper.getById(id);
    }

    public Coupon selectByStockId(String stockId) {
        Query query = new Query();
        query.eq("t.stock_id", stockId);
        query.join("join merchant t2 on t.parent_code = t2.code");
        List<String> column = Arrays.asList("t.*, t2.name as merchantName, t2.address");
        List<Map<String, Object>> mapList = mapper.listMap(column, query);
        List<Coupon> list = MyBeanUtil.mapListToObjList(mapList, Coupon.class);
        return list.get(0);
    }

    public List<Coupon> selectAllByParentCode(String code, Integer status, String stockType, Integer type) {
        Query query = new Query();
        query.likeRight("parent_code", code);
        if (status != null) {
            query.eq("status", status);
        }
        if (StringUtils.isNotBlank(stockType)) {
            query.eq("stock_type", stockType);
        }
        if (type != null) {
            query.eq("type", type);
        }
        return mapper.list(query);
    }

    public List<Coupon> selectPage(Coupon queryObj, String loginCode, String sortField, String sortOrder) {
        Query query = new Query();
        if (StringUtils.isNotBlank(loginCode)) {
            query.likeRight("t.parent_code", loginCode);
        }
        if (StringUtils.isNotBlank(queryObj.getStockName())) {
            query.like("t.stock_name", queryObj.getStockName());
        }
        if (StringUtils.isNotBlank(queryObj.getStockId())) {
            query.like("t.stock_id", queryObj.getStockId());
        }
        if (StringUtils.isNotBlank(queryObj.getParentCode())) {
            query.likeRight("t.parent_code", queryObj.getParentCode());
        }
        if (queryObj.getStatus() != null) {
            query.eq("t.status", queryObj.getStatus());
        }
        if (queryObj.getType() != null) {
            query.eq("t.type", queryObj.getType());
        }
        if (queryObj.getAvailableBeginTime() != null) {
            query.lt("t.available_begin_time", queryObj.getAvailableBeginTime());
        }
        if (queryObj.getAvailableEndTime() != null) {
            query.gt("t.available_end_time", queryObj.getAvailableEndTime());
        }
        if (StringUtils.isNotBlank(queryObj.getStockType())) {
            query.eq("t.stock_type", queryObj.getStockType());
        }
        if (StringUtils.isNotBlank(sortField) && StringUtils.isNotBlank(sortOrder)) {
            query.orderby("t." + sortField, "ascend".equals(sortOrder) ? Sort.ASC : Sort.DESC);
        }
        query.orderby("t.id", Sort.DESC);
        query.orderby("t.sort_no", Sort.DESC);


        query.join("join merchant t2 on t.parent_code = t2.code");
        List<String> column = Arrays.asList("t.*, t2.name as merchantName");
        List<Map<String, Object>> mapList = mapper.listMap(column, query);
        List<Coupon> list = MyBeanUtil.mapListToObjList(mapList, Coupon.class);
        return list;
    }

    @Transactional
    public void saveOrUpdate(Coupon entity) {
        if (entity.getId() == null) { //新增
            String[] codes = entity.getParentCode().split("-");
            SysCompany company = companyService.selectByCode(codes[0]);
            WxApiV3CouponService wxApiV3CouponService = new WxApiV3CouponService(company);
            String result = wxApiV3CouponService.selectStocks(company.getWxMchId(), entity.getStockId());
            JSONObject json = JSON.parseObject(result);
            String date1 = DateUtils.formatDate(DateUtils.parseDate(json.getString("available_begin_time")));
            entity.setAvailableBeginTime(date1);
            String date2 = DateUtils.formatDate(DateUtils.parseDate(json.getString("available_end_time")));
            entity.setAvailableEndTime(date2);
            entity.setDescription(json.getString("description"));
            entity.setDistributedCoupons(json.getInteger("distributed_coupons"));
            entity.setNoCash(json.getBoolean("no_cash"));
            entity.setSingleitem(json.getBoolean("singleitem"));
            entity.setStockCreatorMchid(json.getString("stock_creator_mchid"));
            entity.setStockName(json.getString("stock_name"));
            entity.setStockType(json.getString("stock_type"));

            JSONObject stockUseRule = json.getJSONObject("stock_use_rule");
            entity.setCombineUse(stockUseRule.getBoolean("combine_use"));
            entity.setMaxCoupons(stockUseRule.getInteger("max_coupons"));
            entity.setMaxCouponsPerUser(stockUseRule.getInteger("max_coupons_per_user"));

            JSONObject fixedNormalCoupon = stockUseRule.getJSONObject("fixed_normal_coupon");
            entity.setCouponAmount(fixedNormalCoupon.getInteger("coupon_amount"));
            entity.setTransactionMinimum(fixedNormalCoupon.getInteger("transaction_minimum"));


            entity.setStatus(1);
            mapper.saveIgnoreNull(entity);
        }
        if (entity.getFilename() != null) {
            UploadFile uploadFile = new UploadFile();
            uploadFile.setMasterId(entity.getId());
            uploadFile.setFilename(entity.getFilename());
            uploadFile.setMasterType(3);
            String fileUrl = uploadFileService.updateUploadFile2(uploadFile);
            entity.setCouponPicUrl(fileUrl);
        }

        mapper.updateIgnoreNull(entity);
    }


    public void saveOrUpdate2(Coupon entity) {
        if (entity.getId() == null) { //新增
            String[] codes = entity.getParentCode().split("-");
            SysCompany company = companyService.selectByCode(codes[0]);
            WxApiV3CouponService wxApiV3CouponService = new WxApiV3CouponService(company);
            Merchant merchant = merchantService.selectByCode(entity.getParentCode());

            Map postData = new HashMap();
            postData.put("stock_name", entity.getStockName());
            postData.put("belong_merchant", merchant.getSubMchId());
            postData.put("goods_name", entity.getDescription());
            postData.put("stock_type", "NORMAL");
            postData.put("out_request_no", System.currentTimeMillis() + "");
            postData.put("coupon_code_mode", "WECHATPAY_MODE");

            //核销规则
            Map coupon_available_time = new HashMap();
            coupon_available_time.put("available_begin_time", DateUtils.formatDate(DateUtils.paseDatetime(entity.getAvailableBeginTime()), "yyyy-MM-dd'T'HH:mm:ss.SSS") + "+08:00");
            coupon_available_time.put("available_end_time", DateUtils.formatDate(DateUtils.paseDatetime(entity.getAvailableEndTime()), "yyyy-MM-dd'T'HH:mm:ss.SSS") + "+08:00");
            Map fixed_normal_coupon = new HashMap();
            fixed_normal_coupon.put("discount_amount", entity.getCouponAmount());
            fixed_normal_coupon.put("transaction_minimum", entity.getTransactionMinimum());
            Map coupon_use_rule = new HashMap();
            coupon_use_rule.put("coupon_available_time", coupon_available_time);
            coupon_use_rule.put("fixed_normal_coupon", fixed_normal_coupon);
            coupon_use_rule.put("use_method", "OFF_LINE");

            //发放规则
            Map stock_send_rule = new HashMap();
            stock_send_rule.put("max_amount", entity.getMaxAmount());
            stock_send_rule.put("max_coupons", entity.getMaxCoupons());
            stock_send_rule.put("max_coupons_per_user", entity.getMaxCouponsPerUser());

            postData.put("coupon_use_rule", coupon_use_rule);
            postData.put("stock_send_rule", stock_send_rule);

            Customer customer = customerService.selectByCode(merchant.getParentCode());
            Map notify_config = new HashMap();
            notify_config.put("notify_appid", customer.getMiniAppid());

            postData.put("notify_config", notify_config);

            String result = wxApiV3CouponService.createMerCoupon(postData);
            JSONObject json = JSON.parseObject(result);
            entity.setStockId(json.getString("stock_id"));
            entity.setDistributedCoupons(0);
            entity.setStatus(1);
            entity.setStockCreatorMchid(company.getWxMchId());
            mapper.saveIgnoreNull(entity);
        }
        if (entity.getFilename() != null) {
            UploadFile uploadFile = new UploadFile();
            uploadFile.setMasterId(entity.getId());
            uploadFile.setFilename(entity.getFilename());
            uploadFile.setMasterType(3);
            String fileUrl = uploadFileService.updateUploadFile2(uploadFile);
            entity.setCouponPicUrl(fileUrl);
        }

        mapper.updateIgnoreNull(entity);
    }

    public void updateStatus(Long id) {
        Coupon coupon = mapper.getById(id);
        coupon.setStatus(coupon.getStatus() == 1 ? 2 : 1);
        mapper.update(coupon);
    }

    /**
     * 免费领取和积分兑换代金券 领取成功数量+1
     *
     * @param coupon
     * @param member
     */
    @Transactional
    public void sendCoupon(Coupon coupon, Member member, Long couponOrderId) {
        String[] codes = coupon.getParentCode().split("-");
        SysCompany company = companyService.selectByCode(codes[0]);
        WxApiV3CouponService wxApiV3CouponService = new WxApiV3CouponService(company);
        String outTradeNo = System.currentTimeMillis() + "";
        String result = wxApiV3CouponService.sendCoupons(company.getWxAppId(), company.getWxMchId(),
                coupon.getStockId(), member.getPayOpenid(), outTradeNo);
        String couponId = JSON.parseObject(result).getString("coupon_id");

        //修改发券数量
        updateDistributedCoupons(coupon.getId());
        //保存领券记录
        couponOrderService.saveCouponOrder(coupon, couponOrderId, member.getMiniOpenid(), member.getNickName(), member.getAvatarUrl(), outTradeNo, couponId, null);
    }

    /**
     * 购买代金券，购买之前已处理数量，这里不处理
     * @param coupon
     * @param member
     * @param couponOrderId
     */
    @Transactional
    public void sendCoupon2(Coupon coupon, Member member, Long couponOrderId) {
        String[] codes = coupon.getParentCode().split("-");
        SysCompany company = companyService.selectByCode(codes[0]);
        WxApiV3CouponService wxApiV3CouponService = new WxApiV3CouponService(company);
        String outTradeNo = System.currentTimeMillis() + "";
        String result = wxApiV3CouponService.sendCoupons(company.getWxAppId(), company.getWxMchId(),
                coupon.getStockId(), member.getPayOpenid(), outTradeNo);
        String couponId = JSON.parseObject(result).getString("coupon_id");
        //保存领券记录
        couponOrderService.saveCouponOrder(coupon, couponOrderId, member.getMiniOpenid(), member.getNickName(), member.getAvatarUrl(), outTradeNo, couponId, null);
    }

    /**
     * 已发券数量加1++.
     * @param id
     */
    private void updateDistributedCoupons(Long id) {
//        coupon.setDistributedCoupons(coupon.getDistributedCoupons() + 1);
//        mapper.updateIgnoreNull(coupon);
        mapper.updateDistributedCoupons(id);
    }

    /**
     * 已发券数量减1.
     * @param id
     */
    public void updateDistributedCouponsSub(Long id) {
        mapper.updateDistributedCouponsSub(id);
    }


    /**
     * 购买优惠券
     *
     * @param coupon
     * @param member
     */
    @Transactional
    public Object buyCoupon(Coupon coupon, Member member) {
        //修改发券数量
        this.updateDistributedCoupons(coupon.getId());

        String outTradeNo = System.currentTimeMillis() + "";
        Trade trade = new Trade();
        trade.setParentCode(coupon.getParentCode());
        trade.setProductNo(coupon.getStockId());
        trade.setProductName(coupon.getStockName());
        trade.setPrice(coupon.getAmount());
        trade.setOutTradeNo(outTradeNo);
        trade.setMiniOpenid(member.getMiniOpenid());
        trade.setNickName(member.getNickName());
        trade.setStatus(0);
        trade.setSendStatus(1);
        trade.setFileUrl(coupon.getCouponPicUrl());
        tradeService.save(trade);

        String[] codes = coupon.getParentCode().split("-");
        SysCompany company = companyService.selectByCode(codes[0]);
        Merchant merchant = merchantService.selectByCode(coupon.getParentCode());
        WxpayService wxpayService = new WxpayService(company, merchant.getSubMchId(), merchant.getSubAppid());
        JSONObject result = wxpayService.sendJsApi(outTradeNo, coupon.getAmount() + "",
                notify_url + "/api/notify/wxPayBack", member.getMiniOpenid());
        result.put("outTradeNo", outTradeNo);
        return result;
    }

    /**
     * 积分兑换优惠券
     * @param coupon
     * @param member
     */
    @Transactional
    public String exchangeCoupon(Coupon coupon, Member member) {
        String outTradeNo = System.currentTimeMillis() + "";

        int temp = member.getIntegral() - coupon.getAmount();
        if (temp < 0) {
            throw new BusinessException("您的积分不足");
        }
        //更新积分
        member.setIntegral(temp);
        memberService.updateMember(member);
        //保存积分明细记录
        memberIntegralService.save(coupon.getAmount(), member.getMiniOpenid(), null, 2, "兑换" + coupon.getStockName());
        if (coupon.getStockType().equals("merNORMAL")) {
            //生成订单
            Trade trade = new Trade();
            trade.setParentCode(coupon.getParentCode());
            trade.setProductNo(coupon.getStockId());
            trade.setProductName(coupon.getStockName());
            trade.setPrice(coupon.getAmount());
            trade.setOutTradeNo(outTradeNo);
            trade.setMiniOpenid(member.getMiniOpenid());
            trade.setNickName(member.getNickName());
            trade.setStatus(1);
            trade.setSendStatus(1);
            trade.setFileUrl(coupon.getCouponPicUrl());
            tradeService.save(trade);

            //修改发券数量
            this.updateDistributedCoupons(coupon.getId());
        } else {
            //如果是代金券 调用发券
            sendCoupon(coupon, member, null);
        }
        return outTradeNo;
    }

    public Map<String, Object> getMerCouponSign(String code, String outTradeNo, String stockId) {
        SysCompany company = companyService.selectByCode(code);
        SortedMap<String, String> map = new TreeMap();
        map.put("out_request_no0", outTradeNo);
        map.put("send_coupon_merchant", company.getWxMchId());
        map.put("stock_id0", stockId);
        String sha256Sign = MD5Utils.getSignCoupon(map, company.getWxMchKey());

        Map<String, Object> resultMap = new HashMap<>();
        JSONArray paramsArray = new JSONArray();
        JSONObject paramObject = new JSONObject();
        paramObject.put("stock_id", stockId);
        paramObject.put("out_request_no", outTradeNo);
        paramsArray.add(paramObject);
        resultMap.put("send_coupon_params", paramsArray);
        resultMap.put("sign", sha256Sign);
        resultMap.put("send_coupon_merchant", company.getWxMchId());
        return resultMap;
    }

    /**
     * 核销代金券通知
     *
     * @param str
     */
    @Transactional
    public void consumeCoupon(String str) {
        JSONObject json = JSON.parseObject(str);
        //代金券id
        String coupon_id = json.getString("coupon_id");
        //创建批次的商户号
        String stock_creator_mchid = json.getString("stock_creator_mchid");
        //批次号
        String stock_id = json.getString("stock_id");
        //代金券名称
        String coupon_name = json.getString("coupon_name");

        JSONObject normal_coupon_information = json.getJSONObject("normal_coupon_information");
        //面额
        String coupon_amount = normal_coupon_information.getString("coupon_amount");
        //门槛
        String transaction_minimum = normal_coupon_information.getString("coupon_amount");

        JSONObject consume_information = json.getJSONObject("consume_information");
        //核销时间
        String consume_time = consume_information.getString("consume_time");
        String consumetime = DateUtils.formatDate(DateUtils.parseDate(consume_time, "yyyy-MM-dd'T'HH:mm:ss"), "yyyy-MM-dd HH:mm:ss");
        //核销商户号
        String consume_mchid = consume_information.getString("consume_mchid");
        //核销订单号
        String transaction_id = consume_information.getString("transaction_id");
        Merchant merchant = merchantService.selectBySubMchId(consume_mchid);
        CouponOrder couponOrder = couponOrderService.selectByCouponCode(coupon_id);
        if (couponOrder.getStatus() == 1) { //未使用
            couponOrder.setConsumeMchid(consume_mchid);
            couponOrder.setMerchantName(merchant != null ? merchant.getName() : null);
            couponOrder.setTransactionId(transaction_id);
            couponOrder.setConsumeTime(consumetime);
            couponOrder.setStatus(2);
            couponOrderService.saveOrUpdate(couponOrder);

            //增加积分
            Integer integral = new Double(Integer.parseInt(transaction_minimum) / 100).intValue();
            Member member = memberService.selectByMiniOpenId(couponOrder.getMiniOpenid());
            member.setIntegral(member.getIntegral() + integral);
            memberService.updateMember(member);

            //保存积分明细记录
            memberIntegralService.save(integral, member.getMiniOpenid(), couponOrder.getOutTradeNo(), 1, "核销" + coupon_name);
        }
    }

    /**
     * 核销商家券
     * @param couponCode
     */
    public void useMerCoupon(String couponCode, String merchantCode) {
        CouponOrder couponOrder = couponOrderService.selectByCouponCode(couponCode);
        SysCompany company = companyService.selectByCode(couponOrder.getParentCode().split("-")[0]);
        WxApiV3CouponService wxApiV3CouponService = new WxApiV3CouponService(company);
        String result = wxApiV3CouponService.useMerCoupon(couponCode, company.getWxAppId(), couponOrder.getTransactionId());
        JSONObject json = JSON.parseObject(result);
        Merchant merchant = merchantService.selectByCode(merchantCode == null ? couponOrder.getParentCode() : merchantCode);
        couponOrder.setConsumeMchid(merchant.getSubMchId());
        couponOrder.setMerchantName(merchant.getName());

        String date = json.getString("wechatpay_use_time");
        date = DateUtils.formatDate(DateUtils.parseDate(date, "yyyy-MM-dd'T'HH:mm:ss"), "yyyy-MM-dd HH:mm:ss");
        couponOrder.setConsumeTime(date);
        couponOrder.setStatus(2);
        couponOrder.setStockId(json.getString("stock_id"));
        couponOrderService.saveOrUpdate(couponOrder);

        //增加积分
        Integer integral = new Double(couponOrder.getPrice() * 0.01).intValue();
        Member member = memberService.selectByMiniOpenId(couponOrder.getMiniOpenid());
        member.setIntegral(member.getIntegral() + integral);
        memberService.updateMember(member);

        //保存积分明细记录
        memberIntegralService.save(integral, member.getMiniOpenid(), couponOrder.getOutTradeNo(), 1, "核销" + couponOrder.getStockName());

    }

    public List<Coupon> selectAllByIDs(List<Long> couponIds) {
        List<Coupon> list = new ArrayList<>();
        if (couponIds != null && couponIds.size() > 0) {
            Query query = new Query();
            query.in("id", couponIds);
            list = mapper.list(query);
        }
        return list;
    }

    /**
     * 小程序发券成功后处理逻辑
     * @param outTradeNo
     * @param couponCode
     * @return
     */
    @Transactional
    public void sendCouponSuccess(String outTradeNo, String couponCode) {
        CouponOrder couponOrder = couponOrderService.selectByCouponCode(couponCode);
        if (couponOrder == null) {
            Trade trade = tradeService.selectByOutTradeNo(outTradeNo);
            trade.setSendStatus(2);
            tradeService.update(trade);
            Coupon coupon = this.selectByStockId(trade.getProductNo());

            Member member = memberService.selectByMiniOpenId(trade.getMiniOpenid());
            //保存领券记录
            couponOrderService.saveCouponOrder(coupon, null, member.getMiniOpenid(), member.getNickName(), member.getAvatarUrl(), outTradeNo, couponCode, trade.getTransactionId());
        }
    }


    public void deleteById(Long id) {
        mapper.deleteById(id);
    }

    public void update(Coupon coupon) {
        mapper.updateIgnoreNull(coupon);
    }

    /**
     * 临时使用发放赛达的代金券
     * @param coupon
     * @param member
     */
    @Transactional
    public void test20200329(Coupon coupon, Member member) {
        String outTradeNo = System.currentTimeMillis() + "";
        int amountTemp = member.getAmount() - coupon.getAmount();
        if (amountTemp < 0) {
            throw new BusinessException("您的助力点不足");
        }
        //更新助力点
        member.setAmount(amountTemp);
        memberService.updateMember(member);

        SysCompany company = companyService.selectById(5L);
        WxApiV3CouponService wxApiV3CouponService = new WxApiV3CouponService(company);
        String result = wxApiV3CouponService.sendCoupons(company.getWxAppId(), company.getWxMchId(),
                coupon.getStockId(), member.getPayOpenid(), outTradeNo);
        String couponId = JSON.parseObject(result).getString("coupon_id");
        //修改发券数量
        updateDistributedCoupons(coupon.getId());
        //保存领券记录
        couponOrderService.saveCouponOrder(coupon, null, member.getMiniOpenid(),
                member.getNickName(), member.getAvatarUrl(), outTradeNo, couponId, null);
    }

    public List<Coupon> selectAllCoupon(String merchantCode, String parentCode) {
        Query query = new Query();
        if (StringUtils.isNotBlank(merchantCode)) {
            query.eq("parent_code", merchantCode);
        }
        if (StringUtils.isNotBlank(parentCode)) {
            query.likeRight("parent_code", parentCode);
        }
        return mapper.list(query);
    }

    /**
     * 查询奖品
     * @param activityId
     * @return
     */
    public List<Coupon> selectLuckDraw(Long activityId) {
        Query query = new Query();
        query.sql("t.distributed_coupons < t.max_coupons");
        query.gt("t.available_end_time", new Date());
        query.eq("t.is_deleted", false);
        query.eq("t2.activity_id", activityId);
        query.join("join activity_detail t2 on t.id = t2.coupon_id");

        List<String> column = Arrays.asList("t.*, t2.rate");
        List<Map<String, Object>> mapList = mapper.listMap(column, query);
        List<Coupon> list = MyBeanUtil.mapListToObjList(mapList, Coupon.class);
        return list;
    }

    /**
     * 显示奖品
     * @param id
     * @return
     */
    public List<Coupon> selectType2ByActivityId(Long id) {
        Query query = new Query();
        query.eq("t2.activity_id", id);
        query.join("join activity_detail t2 on t.id = t2.coupon_id");
        return mapper.list(query);
    }
}
